//
//  Created by Flutter on 2021/4/12.
//

import Foundation
import LMDB

public struct AsyncStore<T: Store> {
    private let store: T
    private let queue = StorageService.queue
    private let mainQueue = DispatchQueue.main

    public init(store: T) { self.store = store }
}

public extension AsyncStore {
    func put<V: DataConvertible, K: DataConvertible>(value: V, forKey key: K, complete: @escaping (Result<Void, Swift.Error>) -> Void) {
        queue.async {
            do {
                try store.put(value: value, forKey: key)
                mainQueue.async { complete(.success(())) }
            } catch {
                mainQueue.async { complete(.failure(error)) }
            }
        }
    }

    func get<V: DataConvertible, K: DataConvertible>(key: K, complete: @escaping (Result<V?, Swift.Error>) -> Void) {
        queue.async {
            do {
                let value: V? = try store.get(key: key)
                mainQueue.async { complete(.success(value)) }
            } catch {
                mainQueue.async { complete(.failure(error)) }
            }
        }
    }

    func delete<K: DataConvertible>(key: K, complete: @escaping (Result<Void, Swift.Error>) -> Void) {
        queue.async {
            do {
                try store.delete(key: key)
                mainQueue.async { complete(.success(())) }
            } catch {
                mainQueue.async { complete(.failure(error)) }
            }
        }
    }
}

public extension AsyncStore {
    func put<StorableObject: Storable>(storableObject: StorableObject, complete: @escaping (Result<Void, Swift.Error>) -> Void) {
        queue.async {
            do {
                let key = StorableObject.key
                try store.put(value: storableObject, forKey: key)
                mainQueue.async { complete(.success(())) }
            } catch {
                mainQueue.async { complete(.failure(error)) }
            }
        }
    }

    func get<StorableObject: Storable>(complete: @escaping (Result<StorableObject?, Swift.Error>) -> Void) {
        queue.async {
            do {
                let key = StorableObject.key
                let value: StorableObject? = try store.get(key: key)
                mainQueue.async { complete(.success(value)) }
            } catch {
                mainQueue.async { complete(.failure(error)) }
            }
        }
    }
}

public extension AsyncStore {
    func empty(complete: @escaping (Result<Void, Swift.Error>) -> Void) throws {
        queue.async {
            do {
                try store.empty()
                mainQueue.async { complete(.success(())) }
            } catch {
                mainQueue.async { complete(.failure(error)) }
            }
        }
    }
}

